/*
 Copyright (c) Whitemice Consulting, 2007, 2008, 2009
 Adam Tauno Williams <awilliam@whitemice.org>
 License: MIT/X11

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/
using System;
using System.Net;
using System.Linq;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using Whitemice.ZOGI;
using Whitemice.ZOGI.GtkForms;
using Whitemice.ZOGI.GtkWidgets;
using Gtk;
using GLib;

namespace Whitemice.Consonance
{	
  /// <summary>
  /// Main window for Consonance app 
  /// </summary>
	public partial class MainWindow : Gtk.Window, IEntityView, IZOGIWidget
	{
		protected SplashPanel					                splashPanel;
		protected MultiResultCallback                 callback;
		
		/// <summary>
		/// ctor
		/// </summary>
		public MainWindow() : base("")
		{
			this.Build();

			//callback = new MultiResultCallback(this.ReceiveDataCallback);
      
			projectSearch.StatusLabel = statusLabel;
			enterpriseSearch.StatusLabel = statusLabel;
			contactSearch.StatusLabel = statusLabel;
			StatusMessage = "Welcome to Consonance";
			splashPanel = new SplashPanel();
			projectSearch.PopupEnabled = true;
			OfflineMode();
			SetupHandlers();
			for( int i = 0;i < mainNotebook.NPages; i++)
				mainNotebook.GetTabLabel(mainNotebook.GetNthPage(i)).ShowAll();
		  GLib.Timeout.Add(500, new TimeoutHandler(this.IdleEvent));
		} // end ctor

    public void ReceiveRPCCall(RPCEventArgs args)
    {
      string command = (args.Context as System.String);
      if (args.HasResults)
      {
        switch(command.Split(':')[0])
        {
          case "remove":
           break;
          case "present":
            Present(args.Payload.ElementAt(0), command.Split(':')[1], args.Exception);
           break;
          case "new":
           break;
        }
      }
    } // end ReceiveRPCCall

		protected void ReceiveTasks(IEnumerable<Entity> tasks)
		{
		  Console.WriteLine("MainWindow.ReceiveTasks");
		} // end ReceiveTasks
					
		protected virtual void OnOnlineActivated(
			object sender, 
			System.EventArgs args)
		{
			Login 								dialog;
			ResponseType					response;
			
			dialog = new Login(string.Empty, string.Empty, string.Empty);
			dialog.Show();
			response = (ResponseType)dialog.Run();
			if (response == ResponseType.Ok)
			{
				Server.Connection.Connect(
					dialog.Hostname,
          80,
					dialog.Username, 
					dialog.Password);
				if(Server.Connection.Connected)
				{
					OnlineMode();
				}	else 
						{
							OfflineMode();
							new MessageBox("Failed to establish connection with server");
						}
			}
			dialog.Destroy();
		} // end OnOnlineActivate 
		
		/// <summary>
		/// Receive an exception from the server object
		/// </summary>
		/// <param name="_exception">
		/// A <see cref="Exception"/>
		/// </param>
		/// <param name="_faultCode">
		/// A <see cref="System.Int32"/>
		/// </param>
		/// <param name="_faultString">
		/// A <see cref="System.String"/>
		/// </param>
		protected virtual void OnServerException(
			Exception exception,
			int faultCode,
			string faultString)
		{
		  // go into the main thread
			Application.Invoke
			(
				delegate 
				{ 
					new ExceptionDialog(
								exception, 
								faultCode, 
								faultString);
				}
			);
		} // end OnServerException 
		
		/// <summary>
		/// Receive a user message from the server
		/// </summary>
		/// <param name="_message">
		/// A <see cref="System.String"/>
		/// </param>
		protected virtual void OnUserMessage(string message)
		{
		  // go into the main thread
			Application.Invoke
			( 
			  delegate
				{
				  SetStatusMessage("User message received from server.");
					MessageBox(
						message, 
						Gtk.DialogFlags.DestroyWithParent,
						Gtk.MessageType.Info, 
						Gtk.ButtonsType.Close);
				}
			);
		} // end OnUserMessage 

    /// <summary>
    /// Receive plugin data from the server
    /// </summary>
    /// <param name="_data">
    /// A <see cref="Hashtable"/>
    /// </param>
		protected virtual void OnReceivedPluginData(Hashtable _data)
		{
		  Application.Invoke
		  (
		    delegate
		    {
		      SetStatusMessage("Received plugin data from server.");
		    }
		  );
		}	// end OnReceivedPluginData 

    /// <summary>
    /// Preferences activated
    /// </summary>
    /// <param name="_o">
    /// A <see cref="System.Object"/>
    /// </param>
    /// <param name="_args">
    /// A <see cref="System.EventArgs"/>
    /// </param>
		protected virtual void OnPreferencesActivated(
			object _o, 
			System.EventArgs _args)
		{
		} // end OnPreferencesActivated 
		
		protected virtual void OnPreferencesDestroyed(
			object _o, 
			System.EventArgs _args)
		{
    }

		protected virtual void OnQuitActivated(
			object _o, 
			System.EventArgs _args)
		{	
		  SetStatusMessage("Quiting...");
		  Consonance.Quit(); 
		}

		protected virtual void OnFindActivated(
			object _sender, 
			System.EventArgs _e)
		{
		}
		
		public void MessageBox(
			string _message, 
			DialogFlags _flags,
			MessageType _messageType, 
			ButtonsType _buttons)
		{
			MessageDialog dialog;
			dialog = new Gtk.MessageDialog(
				this, 
				_flags, 
				_messageType, 
				_buttons, 
				_message);
			dialog.Run();
			dialog.Destroy();
		}		

		protected virtual void OnNewAppointmentActivated(
			object _sender, 
			System.EventArgs _args)
		{
			Present(new Whitemice.ZOGI.Appointment(), "new", null);
		}

		protected virtual void OnNewContactActivated(
			object _sender, 
			System.EventArgs _args)
		{
			Present(new Whitemice.ZOGI.Contact(), "new", null);
		}

		protected virtual void OnNewEnterpriseActivated(
			object _sender, 
			System.EventArgs _args)
		{
			Present(new Whitemice.ZOGI.Enterprise(), "new", null);
		}

		protected virtual void OnNewProjectActivated(
			object _sender, 
			System.EventArgs _args)
		{
			Present(new Whitemice.ZOGI.Project(), "new", null);
		}

		protected virtual void OnNewTaskActivated(
			object _sender, 
			System.EventArgs _e)
		{
      this.ZLOG("New Task");
			Present(new Whitemice.ZOGI.Task(), "new", null);
		}
		
		protected virtual void OnEventEdit(
      Entity _entity,
			object _context,
			Exception _exception)
		{
		  Present(_entity, "edit", null);
		}

		protected virtual void OnEventView(
      Entity _entity,
			object _context,
			Exception _exception)
		{
		}

		protected virtual void OnEventDelete(
      Entity _entity,
			object _context,
			Exception _exception)		
	  {
		}
		
		protected virtual void OnEventCreate(
      Entity _entity,
			object _context,
			Exception _exception)		
	  {
	    Present(_entity, "new", null);
		}
		
		protected virtual void OnEventMove(
      Entity _entity,
			object _context,
			Exception _exception)
		{
		}

		protected virtual void OnDestroyEvent(
			object _o, 
			Gtk.DestroyEventArgs _args)
		{ Consonance.Quit(); }
		
		protected void SetupHandlers()
		{
			contactSearch.OnContactEdit = new EntityEventHandler(Present);
			contactSearch.OnContactRemove = new EntityEventHandler(Remove);
      contactSearch.PopupEnabled = true;
			enterpriseSearch.OnEnterpriseEdit = new EntityEventHandler(Present);
			enterpriseSearch.OnEnterpriseRemove = new EntityEventHandler(Remove);
			enterpriseSearch.PopupEnabled = true; 
			taskLists.OnTaskAccept += new EntityEventHandler(Present);
			taskLists.OnTaskActivate += new EntityEventHandler(Present);
			taskLists.OnTaskArchive += new EntityEventHandler(Present);
			taskLists.OnTaskComment += new EntityEventHandler(Present);
			taskLists.OnTaskDone += new EntityEventHandler(Present);
			taskLists.OnTaskEdit += new EntityEventHandler(Present);
			taskLists.OnTaskReject += new EntityEventHandler(Present);
			projectSearch.OnProjectEdit += new EntityEventHandler(Present);
			projectSearch.PopupEnabled = true;
      /*
			daystrip.SetPositionToCurrent();
			daystrip.OnDeleteEvent += new EntityEventHandler(OnEventDelete);
			daystrip.OnEditEvent += new EntityEventHandler(OnEventEdit);
			daystrip.OnDropEvent += new EntityEventHandler(OnEventMove);
			daystrip.OnViewEvent += new EntityEventHandler(OnEventView);
		  daystrip.OnCreateEvent += new EntityEventHandler(OnEventCreate);
      
			ZOGIApplication.Server.OnException += 
				new zOGIExceptionHandler(OnServerException);
			ZOGIApplication.Server.OnUserMessage += 
				new zOGIUserMessageHandler(OnUserMessage);
			ZOGIApplication.Server.OnReceivedPluginData += 
				new zOGIPluginDataHandler(OnReceivedPluginData);
		  */
		}
				
		/// <summary>
		/// Deletion of entity requested.
		/// </summary>
		/// <param name="_entity">
		/// A <see cref="Entity"/>
		/// </param>
		/// <param name="_context">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="_exception">
		/// A <see cref="Exception"/>
		/// </param>
		public virtual void Remove(
			Entity _entity,
			object _context,
			Exception _exception)
		{
			if (GUI.RaiseWindow(_entity))
			{
				// Object is being viewed, present the window and notify user 
				new MessageBox("Object#" + _entity.ObjectId.ToString() + " is currently in use.");
			} else
				{
					if (_entity.CanModify)
					{
						// User has modification privileges
						if (Server.Connection.Delete(_entity))
						{
							// Delete was successful 
							Registry.UnregisterForNotification(_entity, this);
							new MessageBox("Deletion successful.");
						} else 
							{
								// Delete failed 
								new MessageBox("Deletion failed");
							}
					} else 
						{
							// Insufficient privileges to delete object 
							new MessageBox("You lack sufficient privilages to perform the requested action");
						}
				}
		} // end RemoveCallback
    
		/// <summary>
		/// Request to present an entity window
		/// </summary>
		/// <param name="_entity">
		/// A <see cref="Whitemice.ZOGI.Entity"/>
		/// </param>
		/// <param name="_context">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="_exception">
		/// A <see cref="Exception"/>
		/// </param>
		public virtual void Present(Entity entity, object context, Exception exception)
		{
      this.ZLOG("Present {0}#{1} w/context={2}", entity.EntityName, entity.ObjectId, context.ToString());
			switch (entity.EntityName)
			{
			  case "Appointment":
			    if (!(GUI.RaiseWindow(entity)))
			      new AppointmentWindow((entity as Appointment));
			    break;
				case "Contact":
					if (!(GUI.RaiseWindow(entity)))
						new ContactWindow((entity as Contact));
					break;
				case "Enterprise":
					if (!(GUI.RaiseWindow(entity)))
			 		  new EnterpriseWindow((entity as Enterprise));
					break;					
				case "Task":
					switch(context.ToString())
					{
            case "new":
						case "edit":
							if (!(GUI.RaiseWindow(entity)))
								new TaskWindow((entity as Task)).Present();
							break;
				  	case "accept":
							new TaskActionDialog(
								this,
								(entity as Task),
								TaskAction.Accept);
							break;
						case "comment":
							new TaskActionDialog(
								this,
								(entity as Task),
								TaskAction.Comment);							
							break;
						case "reject":
							new TaskActionDialog(
								this,
								(entity as Task),
								TaskAction.Reject);							
							break;
						case "done":
							new TaskActionDialog(
								this,
								(entity as Task),
								TaskAction.Done);							
							break;
						case "archive":
							new TaskActionDialog(
								this,
								(entity as Task),
								TaskAction.Archive);							
							break;
						case "activate":
							new TaskActionDialog(
								this,
								(entity as Task),
								TaskAction.Activate);							
							break;								
					}
					break;
				case "Project":
					if (!(GUI.RaiseWindow(entity)))
						new ProjectWindow((entity as Project));
					break;											
			} // end entity type switch 
		} // end Present 

		protected virtual void OnContactsCRUDActivated (
			object _sender, 
			System.EventArgs _e)
		{
			new ContactCRUD();
		} // end OnContactsCRUDActivated 

		protected virtual void OnDialogInformationActivated (
			object sender, 
			System.EventArgs e)
		{
		} // end OnDialogInformationActivated

		protected virtual void OnPerformanceActivated (
			object sender, 
			System.EventArgs e)
		{
		} // end OnPerformanceActivated

	  protected virtual void OnAboutActivated (object sender, System.EventArgs e)
		{
		} // end OnAboutActivated
		
		protected void OnlineMode()
		{		
			Title = "Consonance (Online)";
			mainNotebook.ShowTabs = true;
			
			mainNotebook.Page = 0;
			mainNotebook.Remove(splashPanel);
			ToolbarOnline.Sensitive = false;
			MenuOnline.Sensitive = false;
			ToolbarFind.Sensitive = true;
			//Consonance.Profile = new UserProfile(Server, "http://www.whitemiceconsulting.com/Consonance.NET");
			//daystrip.FirstDay = DateTime.Today;
			//Server.Search("Team", "all", 128, fillTeams, null);
			//daystrip.RequestData(
			//  DateTime.Now.AddDays(-120), 
			//  DateTime.Now.AddDays(120), 
			//  Server.UserProfile.CalendarPanel);
      taskLists.RefreshTeams();
      taskLists.Refresh(true, true, true);
		} // end OnlineMode 
		
		public void ReceiveEvent(Whitemice.ZOGI.ServerEvent args)
		{
      this.ZLOG("Received server event {0} for {1}", args.Event, args.Entity);
		}
		
		protected void OfflineMode()
		{
			Title = "Consonance (Offline)";
			mainNotebook.ShowTabs = false;
			if (!(mainNotebook.GetNthPage(0) == splashPanel))
				mainNotebook.PrependPage(splashPanel, new Label("Splash"));
			splashPanel.Show();
			mainNotebook.Page = 0;			
			ToolbarOnline.Sensitive = true;
			MenuOnline.Sensitive = true;
			ToolbarFind.Sensitive = false;			
		} // end OfflineMode 
		
		public bool IdleEvent()
		{
      if (Server.Connection != null)
      {
        int count;
        if (Server.Connection.WorkQueueStatus(out count))
          workingPulser.Pulse();
        if (count > 0)
          workingPulser.Text = string.Format("wqd={0} ce={1}%", 
                                             count.ToString(),
                                             Server.Connection.CacheRatio);
        else
          workingPulser.Text = string.Format("wq=Idle ce={0}%",
                                             Server.Connection.CacheRatio);
      }
			return true;
		} // end IdleEvent 
		
		public string StatusMessage
		{
			get { return statusLabel.Text; }
			set { statusLabel.Text = value; }
		} // end StatusMessage 		
		
		public void SetStatusMessage(string _message)
		{
		  statusLabel.Text = _message;
		} // end SetStatusMessage 

		protected virtual void OnQuickIdKeyReleaseEvent (object o, Gtk.KeyReleaseEventArgs args)
		{
		  int           objectId;
      FetchCommand  command;
		  
		  if ((args.Event.Key == Gdk.Key.Return) ||
		      (args.Event.Key == Gdk.Key.KP_Enter))
		  {
		    if ((quickId.Text.Length > 4) ||
		        (quickId.Text.ToLower() == "me"))
		    {
		      try
		      {
		        if (quickId.Text.ToLower() == "me")
		        {
		          objectId = Server.Connection.UserId;
		        } else objectId = Convert.ToInt32(quickId.Text);
            command = new FetchCommand(objectId, 65535, "present:edit");
            command.Callback = callback;
            Server.Connection.RunCommand(command);
		        quickId.Text = string.Empty;
		        SetStatusMessage(string.Format("Request for objectId#{0} issued.", objectId));
		      } catch(Exception exception)
		        {
		          new MessageBox(exception);
		        }
		    } // end if-quickId-text-longer-than-4
		  } // end if-enter-was-pressed
		}
	} // End Class 
} // End namespace 

